
#pragma once

#include <vector>

#include "ttg/all.h"
#include "Stack.h"
#include "BinaryTree.h"

using namespace std;
using namespace ttg;
using namespace ttg::pipeline;

template <class T>
class ttgTreeSplitter :public Node<BinaryTree<T> *, T>
{
	protected:
		virtual void process(BinaryTree<T> *data)
		{
			if (data->getChildCount() <= 256 * 1024)
				sendNext(data->getSum());
			else
			{
				sendNext(data->getValue());
				if (data->getLeft() != NULL)
					sendThis(data->getLeft());
				if (data->getRight() != NULL)
					sendThis(data->getRight());
			}
		}
};

template <class T>
class ttgTreeSumGatherer :public Node<T, T>
{
	private:
		T res;
	protected:
		virtual void onBegin()
				{ res = 0.0f; }
		virtual void onEnd()
				{ sendNext(res); }
		virtual void process(T data)
				{ res += data; }
	public:
		ttgTreeSumGatherer()
			:Node("TreeSumGatherer", true)
				{ /*nothing*/ }
};

//Parallel version of tree summator (via ttg). Return result + elapsed time.
template <class T>
std::pair<T, double> ttgTreeSum(BinaryTree<T> *tree)
{
	static
	Pipeline<BinaryTree<T> *, T> pl(wrap(new ttgTreeSplitter<T>()) + wrap(new ttgTreeSumGatherer<T>()));
	double t_start = services::ServiceBase::_Timer().getSeconds();
	T res = pl.run(tree)[0];
	double t_end = services::ServiceBase::_Timer().getSeconds();
	return std::pair<T, double>(res, t_end - t_start);
}
